#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
1.字符串格式转换
    sprintf以及sscanf函数应用
    sprintf：格式化字符串转换
    sscanf:格式化提取字符串内容
    atoi:将字符串转换为整型
    itoa：将整型数据转换为字符串
    atof:将字符串转换为浮点型
    ftoa:将浮点型数据转换为字符串
2.条件编译
    #define    定义一个预处理宏
    #undef     取消宏的定义
    #if        编译预处理中的条件命令，相当于c语法中的if语句
    #ifdef     判断某个宏是否被定义，若已定义，执行随后的语句
    #ifndef    与#ifdef相反，判断某个宏是否未被定义
    #elif      若#if，#ifdef，#ifndef或前面的#elif条件不满足，则执行#elif之后的语句，相当于c语法中的else-if
    #else      与#if，#ifdef，#ifndef对应，若这些条件不满足，则执行#else之后的语句，相当于c语法中的else
    #endif     #if，#ifdef， #ifndef这些条件命令的结束标志
    defind     与#if,#elif配合使用，判断某个宏是否被定义
3.指针--C语言的灵魂
    3.1概念：指针就是地址
    3.2指针变量的定义：
            数据类型  * 变量名
            int *p;//表示定义了一个可以执行int类型变量的地址的指针变量
            这里*号是一个指针类型说明符
            空指针与野指针
            为了防止指针到处乱指，不小心访问了指针的话,造成内存的泄露甚至是系统的崩溃，最好在定义的时候赋值为NULL，也就是空指针
            int *p=NULL;
    3.3指针与变量
        int a=10；
        int *p=&a；//指针变量p转向了a的地址
        &：取地址符号
        可以通过*p访问a以及修改a的值，这里*：指针运算符/取值运算符
        相同类型的指针变量之间是可以相互赋值的
        注意：指针在指向时，要求做到同类型的指针指向同类型的数据，会影响数据的精度/溢出
    3.4指针大小与类型无关
        在32位平台，所有的指针（地址）都是32位（4字节）
        在64位平台，所有的指针（地址）都是64位（8字节）
    3.5void *万能指针：可以转换为任意类型指针

    3.6常量指针：
        int const *p;或者const int *p;//可以修改指向，但是不能修改指向的空间的值
    3.7指针常量：
        int *const p;//不可以修改指向，但可以修改指向的空间的值
        const在*左边就是常量指针，在*右边就是指针常量

    3.8指针与一维数组
        数组：int num[10];num就是首地址   num<==>&num[0]<==>(num+0)
        因此在数组num中  (num+i)就是&num[i]  所以 *(num+i)就是num[i]
        int num[10];int *p=num;//p指向了数组num的首地址 :num[0]的地址   注意： num不能写自增  
        变量p是允许做 自增/减运算 ，但是它+1 并不一定是一个字节，它+1和它的类型有关系，比如在上一行示例中，p++;将实现将p指向num[1]的地址，也就是移动了4个字节
    
    3.9指针与字符数组/字符串
        char str[20];char *p=str; p++;//此时的p++  移动的是1个字节
        
        char str[20]={"hello"};
        所有上面的定义以后，不允许做这个操作 ：  str="world";  会报错

        指针与字符串
            字符串常量："hello","world" ,字符串常量它是有地址的，看作是一个无名的字符数组，在字符串常量中可以将 字符串当作数组名使用
                例如 "hello"[4]  访问的就是  'o'
            char *p="hello";//p指向了字符串常量 "hello"的首地址
            p="world";//p指向了字符串常量"world"的首地址

*/
int mystrlen(const char*s)
{
    const char *p=s;//首地址
    while(*s)//等价于 *s！=0 等价于*s!='\0'
    s++;

    return s-p;
}
int main(void)
{
    char str[100]={"hello,haha  heihei yes,no!# enen"};
    const char *t=" ,!#";

    printf("strlen:%ld\n",strlen(str));
    printf("mystrlen:%d\n",mystrlen(str));
    printf("str:%s\n",str);
    char *p=strstr(str,"hello");//在str中找指定字符串第一次出现的位置，如果没有就返回NULL
    printf("p:%s\n",p);

    //字符串分割
    char *token=strtok(str,t);//分割字符串
    while(token)//等价于token!=NULL
    {
        printf("token:%s\n",token);
        token=strtok(NULL,t);
    }
}

//指针和字符串
// int main(void)
// {
//     char s1[]={"hello"};
//     printf("s1的size:%zu\n",sizeof(s1));
//     char *sp=s1;//字符指针变量sp指向s1的首地址；
//     *sp='a';
//     printf("sp:%s\n",sp);
//     sp="world";//不会修改s1的内容 它是重新指向了"world"
//     printf("s1:%s\n",s1);
//     sp=s1;//重新指回来
//     scanf("%s",sp);//注意输入的字符长度不能超过6个 因为s1只有6个字节大
//     printf("sp:%s,s1:%s\n",sp,s1);

//     char str[10]="world222";
//     printf("%c\n","hello"[0]);//字符串常量它当做数组名使用可以访问其中的元素
//     char *p="hello";
//     printf("%c\n",p[4]);//通过指针变量p去进行访问
//     p="world";//p可以指向其他的字符串
//     printf("%s\n",p);
//     //*p='a';不会报错 但执行时会出现段错误 因为当前p指向的是一个字符串常量，常量是不允许被修改的
//     //printf("*p=%c\n",*p);

//     //因为p指向了一个字符数组str，所以上面不能修改和指针变量p没有关系
//     p=str;
//     printf("p=%s\n",p);
//     scanf("%s",p);
//     printf("p=%s\n",p);
//     *p='a';
//     printf("p=%c\n",*p);
//     printf("p=%s\n",p);

//     return 0;
// }


// //指针和一维数组
// int main(void)
// {
//     //声明一个数组
//     int num[10]={10,9,8,7,6,5,4,3,2,1};
//     int i;
//     printf("数组每个元素的地址 通过num+i方式:\n");
//     for(i=0;i<10;i++)
//     {
//         printf("%p\t",num+i);//num+i==&num[i]
//     }
//     printf("\n");

//     printf("数组每个元素的地址 通过&num[i]方式:\n");
//     for(i=0;i<10;i++)
//     {
//         printf("%p\t",&num[i]);//num+i==&num[i]
//     }
//     printf("\n");

//     int *p=num;//p指向了num的首地址:&num[0]
//     //通过指针变量p去遍历数组的每一个元素
//     printf("\n---------------------------------------------------\n");
//     printf("通过指针变量p，以及*(num+i)方式遍历数组的元素\n");
//     for(i=0;i<10;i++)
//     {
//         printf("*p:%d  *(num+i):%d \n",*p,*(num+i));
//         p++;//指针指向下一个元素的地址
//     }
//     //上一个循环结束后p指向了"num[10]"
//     printf("\n---------------------------------------------------\n");
//     printf("通过*(p+i)方式遍历数组元素\n");
//     p=num;//p重新指向num的首地址
//     for(i=0;i<10;i++)
//     {
//         printf("*(p+i):%d\t",*(p+i));
//     }
//     printf("\n---------------------------------------------------\n");
//     //此时上一个循环结束p的指向仍旧没有被改变
//     printf("测试p指向的空间的地址的值:%d\n",*p);
//     return 0;

// }


// //指针常量与常量指针
// int main(void)
// {
//     const int a=10;//const修饰了a为常量  所有不能改变
//     //a=100;    错误的

//     int b=10,c=20;

//     const int *p=&b;//常量指针 本质上是一个指针，表示它指向的那段空间是一个常量，不能修改*p，但是可以重新指向其他的地址
//     p=&c;//可以重新指向其他的地址
//     //*p=200;   错误的

//     int const *q=&a;//常量指针
//     q=&b;
//     //*q=200;   错误的

//     int *const r=&b;//指针常量，本质上是一个常量，修饰的是r，r不能修改指向，但是可以修改*r
//     //r=&c;     错误的
//     *r=100;
// }

// //万能指针
// int main(void)
// {
//     int a=10;
//     void *p=NULL;
//     p=&a;
//     *((int *)p)=100;
//     printf("a=%d\n",a);
//     char ch='a';
//     p=&ch;
//     *((char *)p)='b';
//     printf("ch=%c\n",ch);
// }

// //指针大小
// int main(void)
// {
//     int a=10;
//     char b;
//     float c;
//     double d;
//     int *p;
//     char *p1;
//     float *p2;
//     double *p3;
//     printf("a所占字节大小为%zu\n",sizeof(a));
//     printf("b所占字节大小为%zu\n",sizeof(b));
//     printf("c所占字节大小为%zu\n",sizeof(c));
//     printf("d所占字节大小为%zu\n",sizeof(d));

//     printf("p所占字节大小为%zu\n",sizeof(p));
//     printf("p1所占字节大小为%zu\n",sizeof(p1));
//     printf("p2所占字节大小为%zu\n",sizeof(p2));
//     printf("p3所占字节大小为%zu\n",sizeof(p3));
// }

#if (0)
//指针
//交换的是形参  形参的改变 对实参不会有影响
void swap(int a,int b)
{
    int t=a;
    a=b;
    b=t;
}
//交换的是指针
void swap1(int *a,int *b)
{
    int *t;
    t=a;
    a=b;
    b=t;
}
//实现实参数值交换
void swap2(int *a,int *b)
{
    int t;
    t=*a;
    *a=*b;
    *b=t;
}
//实现实参数值交换
void swap3(int *a,int *b)
{
    *a=*a+*b;
    *b=*a-*b;
    *a=*a-*b;
}
int main(void)
{
    int a=10,b=20;
    printf("swap前a=%d,b=%d\n",a,b);
    swap(a,b);
    printf("swap后a=%d,b=%d\n",a,b);

    printf("swap1前a=%d,b=%d\n",a,b);
    swap1(&a,&b);
    printf("swap1后a=%d,b=%d\n",a,b);

    printf("swap2前a=%d,b=%d\n",a,b);
    swap2(&a,&b);
    printf("swap2后a=%d,b=%d\n",a,b);

    printf("swap3前a=%d,b=%d\n",a,b);
    swap3(&a,&b);
    printf("swap3后a=%d,b=%d\n",a,b);
#endif
    // int a=10;
    // int *p=&a;
    // //可以通过p去访问a并且修改a的值
    // printf("&a:%p,p:%p\n",&a,p);
    // printf("&p:%p\n",&p);
    // //*p访问的就是a  这里*是指针运算符/取值运算符
    // printf("a=%d,*p=%d\n",a,*p);
    // *p=100;
    // printf("a=%d,*p=%d\n",a,*p);
    // a=2000;
    // printf("a=%d,*p=%d\n",a,*p);

    // float a=3.14159,b,e,f;
    // int c,d;
    // char str[20]={0};//字符串
    // //sprintf函数：格式化字符串复制
    // printf("a=%.4f\n",a);
    // sprintf(str,"数值为%.4f",a);
    // printf("str:%s\n",str);

    // //sscanf函数
    // scanf("%f",&b);
    // printf("b=%f\n",b);

    // sscanf(str,"数值为%f",&b);
    // printf("b=%f\n",b);

    // //sscanf实现将小数的整数部分和小数部分分离出来
    // strcpy(str,"23.14159");
    // sscanf(str,"%d.%d",&c,&d);
    // printf("c=%d,d=%d\n",c,d);

    // sscanf(str,"%4f%5f",&e,&f);
    // printf("e-%f,f=%f\n",e,f);

    //return 0;
//}